package dbx

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/ClickHouse/clickhouse-go/v2"
)

type ClickHouseSet struct {
	DataBase string   `mapstructure:"database" toml:"database" yaml:"database" json:"database"`
	UserName string   `mapstructure:"username" toml:"username" yaml:"username" json:"username"`
	Password string   `mapstructure:"password" toml:"password" yaml:"password" json:"password"`
	Addrs    []string `mapstructure:"addrs" toml:"addrs" yaml:"addrs" json:"addrs"`
}

type ClickHouse struct {
	DataBase ClickHouseSet `json:"database" yaml:"database" toml:"database"`
	TLS      TLS           `json:"tls,omitempty" yaml:"tls,omitempty" toml:"tls,omitempty"`
}

// clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&read_timeout=20s&http_proxy=?

func (c ClickHouseSet) DSN(query url.Values) string {
	if len(c.Addrs) == 0 {
		panic("no host")
	}

	builder := strings.Builder{}
	builder.WriteString(fmt.Sprintf("clickhouse://%v:%v@", c.UserName, c.Password))
	builder.WriteString(strings.Join(c.Addrs, ","))
	builder.WriteString("/")
	builder.WriteString(c.DataBase)

	encode := c.dsnOptions(query)
	if len(encode) != 0 {
		builder.WriteString("?")
		builder.WriteString(encode)
	}

	return builder.String()
}
func (r ClickHouseSet) dsnOptions(query url.Values) string {
	if query == nil {
		query = url.Values{}
	}

	query.Add("dial_timeout", "200ms")
	query.Add("read_timeout", "20s")

	escape, err := url.QueryUnescape(query.Encode())
	if err != nil {
		panic(err)
	}

	return escape
}

func (c ClickHouse) DSN(query url.Values) string {
	return c.DataBase.DSN(query)
}
func (c ClickHouse) Option(handles ...func(*clickhouse.Options)) clickhouse.Options {
	options := clickhouse.Options{
		Addr: c.DataBase.Addrs,
		Auth: clickhouse.Auth{
			Database: c.DataBase.DataBase,
			Username: c.DataBase.UserName,
			Password: c.DataBase.Password,
		},
		Compression: &clickhouse.Compression{
			Method: clickhouse.CompressionBrotli,
			Level:  5,
		},
		Protocol: clickhouse.HTTP,
	}
	if c.TLS.IsEnable() {
		options.TLS = c.TLS.Tls()
	}

	for _, handle := range handles {
		handle(&options)
	}

	return options
}
